home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / NDK / NDK_3.1 / Examples2 / AmigaGuide / AG_V34 / Source / HyperApp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-16  |  14.3 KB  |  682 lines

  1. /* HyperApp.c
  2.  */
  3.  
  4. #include <exec/types.h>
  5. #include <exec/libraries.h>
  6. #include <intuition/intuition.h>
  7. #include <graphics/gfx.h>
  8. #include <graphics/text.h>
  9. #include <libraries/amigaguide.h>
  10. #include <clib/alib_protos.h>
  11. #include <clib/exec_protos.h>
  12. #include <clib/intuition_protos.h>
  13. #include <clib/graphics_protos.h>
  14. #include <clib/amigaguide_protos.h>
  15. #include <pragmas/amigaguide_pragmas.h>
  16. #include <stdio.h>
  17. #include <string.h>
  18.  
  19. #define    DB(x)    ;
  20.  
  21. struct AppInfo
  22. {
  23.     struct Window *ai_Window;                /* Window pointer */
  24.     BOOL ai_Done;                    /* Done yet? */
  25.     AMIGAGUIDECONTEXT ai_AmigaGuide;            /* Pointer to the AmigaGuide context */
  26.     LONG ai_Region;                    /* Region that the mouse if over */
  27.     struct TextFont *ai_Font;                /* Window font */
  28. };
  29.  
  30. struct FuncTable
  31. {
  32.     VOID (*ft_Func) (struct AppInfo *);
  33. };
  34.  
  35. struct EMenuItem
  36. {
  37.     struct MenuItem em_MenuItem;            /* Embedded menu structure */
  38.     LONG em_MenuID;                    /* Menu ID */
  39. };
  40.  
  41. extern struct Library *SysBase, *DOSBase;
  42. struct Library *IntuitionBase, *GfxBase, *AmigaGuideBase;
  43.  
  44. VOID MainFunc (struct AppInfo *);
  45. VOID QuitFunc (struct AppInfo *);
  46. VOID GadgetFunc (struct AppInfo *);
  47. VOID OkayFunc (struct AppInfo *);
  48. VOID CancelFunc (struct AppInfo *);
  49.  
  50. /* Context ID's to be sent to AmigaGuide */
  51. STRPTR context[] =
  52. {
  53.     "MAIN",
  54.     "QUIT",
  55.     "GADGET",
  56.     "OKAY",
  57.     "CANCEL",
  58.     NULL
  59. };
  60.  
  61. /* Simple little prompts to display within the application window */
  62. STRPTR quickhelp[] =
  63. {
  64.     "HyperApp Main Window",
  65.     "",
  66.     "Transmogrify Objects",
  67.     "Positive Quit",
  68.     "Negative Quit",
  69.     NULL
  70. };
  71.  
  72. struct FuncTable Funcs[] =
  73. {
  74.     MainFunc,
  75.     QuitFunc,
  76.     GadgetFunc,
  77.     OkayFunc,
  78.     CancelFunc,
  79.     NULL
  80. };
  81.  
  82. struct TextAttr TOPAZ8 =
  83. {(STRPTR) "topaz.font", 8, 0, 0};
  84.  
  85. struct IntuiText IText3 =
  86. {
  87.     0, 0, JAM1, 2, 1, &TOPAZ8, "Quit", NULL
  88. };
  89.  
  90. struct EMenuItem MenuItem1 =
  91. {
  92.     NULL, 0, 0, 142, 9, ITEMTEXT | COMMSEQ | ITEMENABLED | HIGHCOMP,
  93.     0, (APTR) & IText3, NULL, 'Q', NULL, MENUNULL, 1L
  94. };
  95.  
  96. struct Menu Menu1 =
  97. {
  98.     NULL, 2, 0, 64, 0, MENUENABLED, "Project", (struct MenuItem *) & MenuItem1
  99. };
  100.  
  101. SHORT BData1[] =
  102. {0, 0, 94, 0, 94, 13, 0, 13, 0, 0};
  103. SHORT BData2[] =
  104. {0, 0, 94, 0, 94, 13, 0, 13, 0, 0};
  105.  
  106. struct Border Border1 =
  107. {0, 0, 1, 0, JAM1, 5, BData1, NULL};
  108. struct Border Border2 =
  109. {0, 0, 1, 0, JAM1, 5, BData2, NULL};
  110.  
  111. struct IntuiText IText1 =
  112. {1, 0, JAM2, 26, 3, &TOPAZ8, "Cancel", NULL};
  113. struct IntuiText IText2 =
  114. {1, 0, JAM2, 40, 3, &TOPAZ8, "OK", NULL};
  115.  
  116. struct Gadget Gadget3 =
  117. {
  118.     NULL, -120, -18, 95, 14, GRELBOTTOM | GRELRIGHT, RELVERIFY, BOOLGADGET,
  119.     (APTR) & Border1, NULL, &IText1, NULL, NULL, 4L, NULL
  120. };
  121.  
  122. struct Gadget Gadget2 =
  123. {
  124.     &Gadget3, 12, -18, 95, 14, GRELBOTTOM, RELVERIFY, BOOLGADGET,
  125.     (APTR) & Border2, NULL, &IText2, NULL, NULL, 3L, NULL
  126. };
  127.  
  128. struct Gadget Gadget1 =
  129. {
  130.     &Gadget2, 12, 27, -40, -48, GADGHCOMP | GRELWIDTH | GRELHEIGHT | SELECTED,
  131.     TOGGLESELECT | RELVERIFY, BOOLGADGET, NULL, NULL, NULL, NULL, NULL,
  132.     2L, NULL
  133. };
  134.  
  135. struct TagItem WinTags[] =
  136. {
  137.     WA_MenuHelp, TRUE,
  138.     TAG_DONE,
  139. };
  140.  
  141. /* NewWindow Structures */
  142. struct ExtNewWindow NewWindowStructure1 =
  143. {
  144.     0, 0, 640, 100, (UBYTE)-1, (UBYTE)-1,
  145.     IDCMP_RAWKEY | IDCMP_CLOSEWINDOW | IDCMP_MENUPICK | IDCMP_MENUHELP |
  146.     IDCMP_GADGETUP | IDCMP_MOUSEMOVE,
  147.     WINDOWSIZING | WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE | WFLG_REPORTMOUSE |
  148.     SIZEBRIGHT | ACTIVATE | NOCAREREFRESH | WFLG_NW_EXTENDED,
  149.     &Gadget1, NULL, "HyperApp (Press HELP over Gadget or Menu)", NULL, NULL,
  150.     320, 50, 65535, 65535, WBENCHSCREEN, WinTags,
  151. };
  152.  
  153. /* Determine if a point is within a rectangle */
  154. ULONG PointInBox (WORD x, WORD y, struct IBox * box)
  155. {
  156.  
  157.     if ((x >= box->Left) &&
  158.     (x <= (box->Left + box->Width)) &&
  159.     (y >= box->Top) &&
  160.     (y <= (box->Top + box->Height)))
  161.     {
  162.     return (1L);
  163.     }
  164.  
  165.     return (0L);
  166. }
  167.  
  168. /* Find the rectangle of a gadget */
  169. VOID gadgetBox (struct Gadget * g, struct IBox * domain, struct IBox * box)
  170. {
  171.  
  172.     /* Set the 'normal' rectangle */
  173.     box->Left = g->LeftEdge;
  174.     box->Top = g->TopEdge;
  175.     box->Width = g->Width;
  176.     box->Height = g->Height;
  177.  
  178.     /* Check for relativity */
  179.     if (g->Flags & GRELRIGHT)
  180.     box->Left += domain->Width - 1;
  181.     if (g->Flags & GRELBOTTOM)
  182.     box->Top += domain->Height - 1;
  183.     if (g->Flags & GRELWIDTH)
  184.     box->Width += domain->Width;
  185.     if (g->Flags & GRELHEIGHT)
  186.     box->Height += domain->Height;
  187. }
  188.  
  189. /* Process menu events */
  190. VOID HandleMenuEvent (struct IntuiMessage * msg)
  191. {
  192.     struct Window *win = msg->IDCMPWindow;
  193.     struct AppInfo *ai = (struct AppInfo *) win->UserData;
  194.     UWORD selection = msg->Code;
  195.     struct EMenuItem *item;
  196.  
  197.     /* Turn off the menu button */
  198.     win->Flags |= RMBTRAP;
  199.  
  200.     /* Process all menu events */
  201.     while (selection != MENUNULL)
  202.     {
  203.     /* Get the MenuItem structure address */
  204.     if (item = (struct EMenuItem *)
  205.         ItemAddress (win->MenuStrip, (LONG) selection))
  206.     {
  207.         (*(Funcs[item->em_MenuID].ft_Func)) (ai);
  208.  
  209.         /* Get the next selection */
  210.         selection = item->em_MenuItem.NextSelect;
  211.     }
  212.     else
  213.     {
  214.         selection = MENUNULL;
  215.     }
  216.     }
  217.  
  218.     /* Turn menu events back on. */
  219.     win->Flags &= ~RMBTRAP;
  220. }
  221.  
  222. /* Process MenuHelp events */
  223. VOID HandleMenuHelp (struct IntuiMessage * msg)
  224. {
  225.     struct Window *win = msg->IDCMPWindow;
  226.     struct AppInfo *ai = (struct AppInfo *) win->UserData;
  227.     struct EMenuItem *item;
  228.     WORD mnum, inum, snum;
  229.  
  230.     mnum = MENUNUM (msg->Code);
  231.     inum = ITEMNUM (msg->Code);
  232.     snum = SUBNUM (msg->Code);
  233.  
  234.     printf ("m %d i %d s %d\n", mnum, inum, snum);
  235.  
  236.     /* Get the MenuItem structure address */
  237.     if (item = (struct EMenuItem *)
  238.     ItemAddress (win->MenuStrip, (LONG) msg->Code))
  239.     {
  240.     /* Set the AmigaGuide context */
  241.     SetAmigaGuideContext (ai->ai_AmigaGuide, item->em_MenuID, NULL);
  242.  
  243.     /* Display the node */
  244.     SendAmigaGuideContext (ai->ai_AmigaGuide, NULL);
  245.     }
  246.     else
  247.     {
  248.     /* No selectable item where help was pressed */
  249.     printf ("No item here\n");
  250.     }
  251. }
  252.  
  253. /* Process MouseMove events */
  254. VOID HandleMouseMove (struct IntuiMessage * msg)
  255. {
  256.     struct Window *win = msg->IDCMPWindow;
  257.     struct AppInfo *ai = (struct AppInfo *) win->UserData;
  258.     struct Gadget *gad = win->FirstGadget;
  259.     struct IBox box;
  260.     LONG region;
  261.  
  262.     if ((msg->MouseX < 0) || (msg->MouseX > win->Width) ||
  263.     (msg->MouseY < 0) || (msg->MouseY > win->Height))
  264.     {
  265.     region = -1L;
  266.     }
  267.     else
  268.     {
  269.     region = 0L;
  270.  
  271.     /* Step through the gadgets to see which one the pointer was over */
  272.     while (gad && (region == 0L))
  273.     {
  274.         /* Calculate the gadget rectangle */
  275.         gadgetBox (gad, (struct IBox *) & (win->LeftEdge), &box);
  276.  
  277.         /* Is the pointer within this gadget? */
  278.         if (PointInBox (msg->MouseX, msg->MouseY, &box))
  279.         {
  280.         /* Is it a system gadget? */
  281.         if (!(gad->GadgetType & GTYP_SYSGADGET))
  282.         {
  283.             /* Set the region */
  284.             region = (LONG) gad->GadgetID;
  285.         }
  286.         }
  287.  
  288.         /* Get the next gadget */
  289.         gad = gad->NextGadget;
  290.     }
  291.     }
  292.  
  293.     if (region != ai->ai_Region)
  294.     {
  295.     WORD tx, ty;
  296.     WORD bx, by;
  297.  
  298.     tx = win->BorderLeft + 8;
  299.     ty = win->BorderTop + 2;
  300.     bx = win->Width - (win->BorderRight + 8);
  301.     by = ty + win->RPort->TxHeight;
  302.  
  303.     SetDrMd (win->RPort, JAM1);
  304.  
  305.     /* Clear the quick help region */
  306.     SetAPen (win->RPort, 0);
  307.     RectFill (win->RPort, tx, ty, bx, by);
  308.  
  309.     /* Remember the region */
  310.     ai->ai_Region = region;
  311.  
  312.     /* Display the quick help if within the window */
  313.     if (region >= 0)
  314.     {
  315.         SetAPen (win->RPort, 1);
  316.         Move (win->RPort, tx, ty + win->RPort->TxBaseline);
  317.         Text (win->RPort, quickhelp[region], strlen (quickhelp[region]));
  318.     }
  319.     }
  320. }
  321.  
  322. /* Process GadgetHelp events */
  323. VOID HandleGadgetHelp (struct IntuiMessage * msg)
  324. {
  325.     struct Window *win = msg->IDCMPWindow;
  326.     struct AppInfo *ai = (struct AppInfo *) win->UserData;
  327.     struct Gadget *gad = win->FirstGadget;
  328.     struct IBox box;
  329.     LONG region;
  330.  
  331.     region = 0L;
  332.  
  333.     /* Step through the gadgets to see which one the pointer was over */
  334.     while (gad && (region == 0L))
  335.     {
  336.     /* Calculate the gadget rectangle */
  337.     gadgetBox (gad, (struct IBox *) & (win->LeftEdge), &box);
  338.  
  339.     /* Is the pointer within this gadget? */
  340.     if (PointInBox (msg->MouseX, msg->MouseY, &box))
  341.     {
  342.         /* Is it a system gadget? */
  343.         if (gad->GadgetType & GTYP_SYSGADGET)
  344.         {
  345.         ULONG sys;
  346.  
  347.         /* Which system gadget? */
  348.         sys = (ULONG) ((gad->GadgetType & 0xF0) / 16);
  349.  
  350.         /* Set the region */
  351.         region = HTFC_SYSGADS + sys;
  352.         }
  353.         else
  354.         {
  355.         /* Set the region */
  356.         region = (LONG) gad->GadgetID;
  357.         }
  358.     }
  359.  
  360.     /* Get the next gadget */
  361.     gad = gad->NextGadget;
  362.     }
  363.  
  364.     /* Set the AmigaGuide context. */
  365.     SetAmigaGuideContext (ai->ai_AmigaGuide, region, NULL);
  366.  
  367.     /* Display the current node */
  368.     SendAmigaGuideContext (ai->ai_AmigaGuide, NULL);
  369. }
  370.  
  371. /* Process Gadget events */
  372. VOID HandleGadgetEvent (struct IntuiMessage * msg)
  373. {
  374.     struct Window *win = msg->IDCMPWindow;
  375.     struct AppInfo *ai = (struct AppInfo *) win->UserData;
  376.     struct Gadget *gad = (struct Gadget *) msg->IAddress;
  377.  
  378.     if (gad)
  379.     {
  380.     (*(Funcs[gad->GadgetID].ft_Func)) (ai);
  381.     }
  382. }
  383.  
  384. /* Process Intuition messages */
  385. VOID HandleIDCMP (struct AppInfo * ai)
  386. {
  387.     struct Window *win = ai->ai_Window;
  388.     struct IntuiMessage *imsg;
  389.  
  390.     while (imsg = (struct IntuiMessage *) GetMsg (win->UserPort))
  391.     {
  392.     switch (imsg->Class)
  393.     {
  394.         case IDCMP_MOUSEMOVE:
  395.         HandleMouseMove (imsg);
  396.         break;
  397.  
  398.         case IDCMP_CLOSEWINDOW:
  399.         ai->ai_Done = TRUE;
  400.         break;
  401.  
  402.         case IDCMP_MENUPICK:
  403.         HandleMenuEvent (imsg);
  404.         break;
  405.  
  406.         case IDCMP_MENUHELP:
  407.         HandleMenuHelp (imsg);
  408.         break;
  409.  
  410.         case IDCMP_GADGETUP:
  411.         HandleGadgetEvent (imsg);
  412.         break;
  413.  
  414.         case IDCMP_RAWKEY:
  415.         if (imsg->Code == 95)
  416.         {
  417.             HandleGadgetHelp (imsg);
  418.         }
  419.  
  420.         break;
  421.     }
  422.  
  423.     /* Reply to the message */
  424.     ReplyMsg ((struct Message *) imsg);
  425.     }
  426. }
  427.  
  428. VOID DisplayError (LONG err)
  429. {
  430.  
  431.     printf ("%s\n", GetAmigaGuideString (err));
  432. }
  433.  
  434. STRPTR err_type[] =
  435. {
  436.     "NO ERROR",
  437.     "HTERR_NOT_ENOUGH_MEMORY",
  438.     "HTERR_CANT_OPEN_DATABASE",
  439.     "HTERR_CANT_FIND_NODE",
  440.     "HTERR_CANT_OPEN_NODE",
  441.     "HTERR_CANT_OPEN_WINDOW",
  442.     "HTERR_INVALID_COMMAND",
  443.     "HTERR_CANT_COMPLETE",
  444.     "HTERR_PORT_CLOSED",
  445.     "HTERR_CANT_CREATE_PORT",
  446.     NULL
  447. };
  448.  
  449. STRPTR msg_type[] =
  450. {
  451.     "<unknown>",
  452.     "StartupMsgID",
  453.     "LoginToolID",
  454.     "LogoutToolID",
  455.     "ShutdownMsgID",
  456.     "ActivateToolID",
  457.     "DeactivateToolID",
  458.     "ActiveToolID",
  459.     "InactiveToolID",
  460.     "ToolStatusID",
  461.     "ToolCmdID",
  462.     "ToolCmdReplyID",
  463.     "ShutdownToolID",
  464.     NULL
  465. };
  466.  
  467. VOID display_msg (struct AmigaGuideMsg * msg)
  468. {
  469.     LONG type, err;
  470.  
  471.     type = msg->agm_Type - StartupMsgID + 1;
  472.     err = msg->agm_Sec_Ret - HTERR_NOT_ENOUGH_MEMORY + 1;
  473.  
  474.     if (err < 0)
  475.     err = 0;
  476.  
  477.     if (type < 0)
  478.     type = 0;
  479.  
  480.     if (msg->agm_Msg.mn_Node.ln_Type == NT_REPLYMSG)
  481.     {
  482.     DB (kprintf ("Reply "));
  483.     }
  484.     else if (msg->agm_Msg.mn_Node.ln_Type == NT_MESSAGE)
  485.     {
  486.     DB (kprintf ("Message "));
  487.     }
  488.     else
  489.     {
  490.     DB (kprintf ("Unknown "));
  491.     }
  492.  
  493.     DB (kprintf ("%s : %s\n", msg_type[type], err_type[err]));
  494. }
  495.  
  496. /* Process AmigaGuide messages */
  497. VOID HandleAmigaGuide (struct AppInfo * ai)
  498. {
  499.     struct AmigaGuideMsg *agm;
  500.  
  501.     /* process amigaguide messages */
  502.     while (agm = GetAmigaGuideMsg (ai->ai_AmigaGuide))
  503.     {
  504.     DB (display_msg (agm));
  505.  
  506.     /* check message types */
  507.     switch (agm->agm_Type)
  508.     {
  509.         /* AmigaGuide is ready for us */
  510.         case ActiveToolID:
  511.         break;
  512.  
  513.         /* This is a reply to our cmd */
  514.         case ToolCmdReplyID:
  515.         if (agm->agm_Pri_Ret)
  516.         {
  517.             DisplayError (agm->agm_Sec_Ret);
  518.         }
  519.         break;
  520.  
  521.         /* This is a status message */
  522.         case ToolStatusID:
  523.         if (agm->agm_Pri_Ret)
  524.         {
  525.             DisplayError (agm->agm_Sec_Ret);
  526.         }
  527.         break;
  528.  
  529.         /* Shutdown message */
  530.         case ShutdownMsgID:
  531.         if (agm->agm_Pri_Ret)
  532.         {
  533.             DisplayError (agm->agm_Sec_Ret);
  534.         }
  535.         break;
  536.  
  537.         default:
  538.         break;
  539.     }
  540.  
  541.     /* Reply to the message */
  542.     ReplyAmigaGuideMsg (agm);
  543.     }
  544. }
  545.  
  546. main (int argc, char **argv)
  547. {
  548.     struct NewAmigaGuide nag = {NULL};
  549.     struct AppInfo ai = {NULL};
  550.  
  551.     /* Initialize the global data */
  552.     ai.ai_Region = -1;
  553.  
  554.     /* Open Intuition library */
  555.     IntuitionBase = OpenLibrary ("intuition.library", 0);
  556.  
  557.     /* Open the graphics library */
  558.     GfxBase = OpenLibrary ("graphics.library", 0);
  559.  
  560.     /* amigaguide.library works with 1.3 and newer versions of the OS */
  561.     if (AmigaGuideBase = OpenLibrary ("amigaguide.library", 33))
  562.     {
  563.     /* Open the window font */
  564.     if (ai.ai_Font = OpenFont (&TOPAZ8))
  565.     {
  566.         /* Open the window */
  567.         if (ai.ai_Window = OpenWindow (&NewWindowStructure1))
  568.         {
  569.         ULONG sigr = 0L, sigi = 0L, sigb = 0L;
  570.  
  571.         /* Set the window font */
  572.         SetFont (ai.ai_Window->RPort, ai.ai_Font);
  573.  
  574.         /* Set the menu */
  575.         SetMenuStrip (ai.ai_Window, &Menu1);
  576.  
  577.         /* Remember the AppInfo */
  578.         ai.ai_Window->UserData = (APTR) & ai;
  579.  
  580.         /* Show that we're not done running the application yet */
  581.         ai.ai_Done = FALSE;
  582.  
  583.         /* Set the application base name */
  584.         nag.nag_BaseName = "HyperApp";
  585.  
  586.         /* Set the document name */
  587.         nag.nag_Name = "hyperapp.guide";
  588.  
  589.         /* establish the base name to use for hypertext ARexx port */
  590.         nag.nag_ClientPort = "AGAPP_HELP";
  591.  
  592.         /* Set up the context table */
  593.         nag.nag_Context = context;
  594.  
  595.         /* Open the help system */
  596.         ai.ai_AmigaGuide = OpenAmigaGuideAsync (&nag, NULL);
  597.  
  598.         /* Get our signal bits */
  599.         sigb = AmigaGuideSignal (ai.ai_AmigaGuide);
  600.         sigi = (1L << ai.ai_Window->UserPort->mp_SigBit);
  601.  
  602.         /* Clear the AmigaGuide context */
  603.         SetAmigaGuideContext (ai.ai_AmigaGuide, 0L, NULL);
  604.  
  605.         /* Continue until done */
  606.         while (!(ai.ai_Done))
  607.         {
  608.             /* Wait for something to happen */
  609.             sigr = Wait (sigb | sigi);
  610.  
  611.             /* Process Intuition messages */
  612.             if (sigr & sigi)
  613.             {
  614.             HandleIDCMP (&ai);
  615.             }
  616.  
  617.             /* Process AmigaGuide messages */
  618.             if (sigr & sigb)
  619.             {
  620.             HandleAmigaGuide (&ai);
  621.             }
  622.         }
  623.  
  624.         /* Shutdown the help system */
  625.         CloseAmigaGuide (ai.ai_AmigaGuide);
  626.  
  627.         /* Do we have a menu? */
  628.         if (ai.ai_Window->MenuStrip)
  629.         {
  630.             /* Clear it */
  631.             ClearMenuStrip (ai.ai_Window);
  632.         }
  633.  
  634.         /* Close the application window */
  635.         CloseWindow (ai.ai_Window);
  636.         }
  637.  
  638.         /* Close the font */
  639.         CloseFont (ai.ai_Font);
  640.     }
  641.  
  642.     /* close the library */
  643.     CloseLibrary (AmigaGuideBase);
  644.     }
  645.  
  646.     CloseLibrary (GfxBase);
  647.     CloseLibrary (IntuitionBase);
  648. }
  649.  
  650. VOID MainFunc (struct AppInfo * ai)
  651. {
  652.  
  653.     printf ("I don't do anything...\n");
  654. }
  655.  
  656. VOID QuitFunc (struct AppInfo * ai)
  657. {
  658.  
  659.     /* All done, guys */
  660.     ai->ai_Done = TRUE;
  661. }
  662.  
  663. VOID GadgetFunc (struct AppInfo * ai)
  664. {
  665.  
  666.     printf ("Pressed the big gadget\n");
  667. }
  668.  
  669. VOID OkayFunc (struct AppInfo * ai)
  670. {
  671.  
  672.     /* All done, guys */
  673.     ai->ai_Done = TRUE;
  674. }
  675.  
  676. VOID CancelFunc (struct AppInfo * ai)
  677. {
  678.  
  679.     /* All done, guys */
  680.     ai->ai_Done = TRUE;
  681. }
  682.